package eda.hashTable;

import eda.util.ADTNoSuchElement;
import eda.util.ADTOverflowException;
import eda.util.ADTUnderflowException;

/**
 * Estrutura representa uma tabela hash que funciona tanto com enderecamento
 * fechado (com chaining) quanto como enderecamento aberto. No caso de enderecamento
 * aberto ela pode funcionar com linear probe, probe quadratico ou double hashing. 
 * A forma de como a tabela vai trabalhar depende das informacoes fornecidas pelo 
 * usuario (se enderecamento aberto ou fechado, e se enderecamento aberto que tipo de 
 * probe). 
 * A estrutura deve ter um tamanho inicial, um tamanho maximo que pode 
 * crescer e um FATOR de crescimento. Quando instanciada a estrutura tem um tamanho 
 * inicial. Quando ela vai crescendo e atinge 75% de sua capacidade, ela aumenta de 
 * tamanho (e deve fazer um rehash nos elementos) de acordo com o fator de crescimento desde que nao atinja ou ultrapasse o tamanho  
 * maximo. A partir dai a estrutura nao pode mais crescer e pode ficar cheia. Use as constantes 
 * definidas em eda.util.Constantes para inicializar os valores internos de sua 
 * estrutura. Faca protected qualquer outro metodo auxiliar.
 */
public class HashTableImpl<K, V> implements HashTable<K, V> {
	
	private HashTable<K,V> chosenHashTable;
	
	protected HashTableImpl(boolean isChaining, int probe){
		
		if ( probe < -1 || probe >  1){
			probe = 1;
		}
		
		if ( isChaining ){
			this.chosenHashTable = new HashTableChaining<K, V>();
		}
		else{
			this.chosenHashTable = new HashTableProbe<K, V>(probe);
		}
		
	}
	
	public HashTableImpl(Integer probe){
		this(false, probe);
	}
	
	public HashTableImpl(){
		this(true, 2);
	}	
	
	@Override
	public boolean isEmpty() {
		return this.chosenHashTable.isEmpty();
	}

	@Override
	public boolean full() {
		return this.chosenHashTable.full();
	}

	@Override
	public int size() {
		return this.chosenHashTable.size();
	}

	@Override
	public void insert(K key, V value) throws ADTOverflowException {
		this.chosenHashTable.insert(key, value);
	}

	@Override
	public void remove(K key) throws ADTUnderflowException, ADTNoSuchElement {
		this.chosenHashTable.remove(key);
	}

	@Override
	public V search(K key){
		return (V)this.chosenHashTable.search(key);
	}

	@Override
	public boolean containsKey(K key){
		return this.chosenHashTable.containsKey(key);
	}
	
	@Override
	public String toString() {
		return this.chosenHashTable.toString();
	}

}
